//
// Created by Gao Shihao on 2023/8/31.
//

#ifndef PLC2LLVM_SUBRANGETYPE_H
#define PLC2LLVM_SUBRANGETYPE_H
#include <plc2llvm/TypeSystem/UserDefType.h>

#include <utility>

namespace plcst {


    class SubRangeType: public UserDefType {

    public:

        explicit SubRangeType(std::string&& name): UserDefType(std::move(name)), lowBound(), upperBound() {}

        explicit SubRangeType(SubRangeType* another) : UserDefType(another) { }

        void setLowBound(std::unique_ptr<BasicType> b);

        void setUpperBound(std::unique_ptr<BasicType> e);

        void setInitValue(std::unique_ptr<BasicType> i);

        [[nodiscard]] TypeKind getTypeKind() const override;

        virtual ConvertionSignal canConvertTo(std::shared_ptr<Type> dest) override{
            if(this->getTypeKind() == dest->getTypeKind()){ //类型相同
                return ConvertionSignal::IMPLICIT_CONVERSION;
            }
            return ConvertionSignal::ERROR_CONVERSION; // TODO
        }

        virtual TypeMsg typeSynthesisForBinaryOperator(ExpressionOperator op, std::shared_ptr<Type> another) override{
            return {nullptr, 2}; // TODO
        }

        virtual TypeMsg typeSynthesisForUnaryOperator(ExpressionOperator op) override {
            return {nullptr, 2};// TODO
        }

        virtual std::shared_ptr<Type> clone() override {
            return std::make_shared<SubRangeType>(this);
        }

    private:
        std::unique_ptr<BasicType> lowBound, upperBound, initValue;

    };

    void SubRangeType::setLowBound(std::unique_ptr<BasicType> b) {
        lowBound = std::move(b);
    }

    void SubRangeType::setUpperBound(std::unique_ptr<BasicType> e) {
        upperBound = std::move(e);
    }

    void SubRangeType::setInitValue(std::unique_ptr<BasicType> i) {
        initValue = std::move(i);
    }

    TypeKind SubRangeType::getTypeKind() const {
        return TypeKind::SUBRANGE;
    }

}
#endif //PLC2LLVM_SUBRANGETYPE_H
